home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 51 / Amiga Format CD51 (2000-03-10)(Future Publishing)(GB)[!][issue 2000-04].iso / -in_the_mag- / workbench / term_4.8 / extras / source / term-source.lha / Sound.c < prev    next >
C/C++ Source or Header  |  1997-07-12  |  22KB  |  1,104 lines

  1. /*
  2. **    Sound.c
  3. **
  4. **    Sound support routines
  5. **
  6. **    Copyright © 1990-1997 by Olaf `Olsen' Barthel
  7. **        All Rights Reserved
  8. **
  9. **    :ts=4
  10. */
  11.  
  12. #ifndef _GLOBAL_H
  13. #include "Global.h"
  14. #endif
  15.  
  16.     /* Double buffering chunk size. */
  17.  
  18. #define BUFFER_SIZE 32768
  19.  
  20.     /* Maximum replay volume. */
  21.  
  22. #define MAX_VOLUME 64
  23.  
  24.     /* Stereo/channel sample type. */
  25.  
  26. typedef LONG SampleType;
  27.  
  28.     /* Channel definitions. */
  29.  
  30. #define SAMPLE_LEFT        2
  31. #define SAMPLE_RIGHT    4
  32. #define SAMPLE_STEREO    6
  33.  
  34.     /* A fixed-point value, 16 bits to the left of
  35.      * the point and 16 to the right. A Fixed is a
  36.      * number of 2**16ths, i.e. 65536ths.
  37.      */
  38.  
  39. typedef LONG Fixed;
  40.  
  41.     /* Unity = Fixed 1.0 = maximum volume */
  42.  
  43. #define Unity 0x10000L
  44.  
  45.     /* Double-buffering information. */
  46.  
  47. struct BufferInfo
  48. {
  49.     LONG    Size;
  50.     UBYTE    Buffer[BUFFER_SIZE];
  51. };
  52.  
  53.     /* Local data. */
  54.  
  55. STATIC struct SignalSemaphore     SoundSemaphore;
  56. STATIC struct SoundInfo            *SoundSlot[SOUND_COUNT];
  57. STATIC BOOL                         SoundInitialized;
  58.  
  59.     /* DeltaUnpack(UBYTE *Src,ULONG Size,BYTE *Dst):
  60.      *
  61.      *    Unpack Fibonacci-delta-encoded data.
  62.      */
  63.  
  64. STATIC VOID
  65. DeltaUnpack(UBYTE *Src,ULONG Size,BYTE *Dst)
  66. {
  67.     STATIC BYTE CodeToDelta[16] = { -34,-21,-13,-8,-5,-3,-2,-1,0,1,2,3,5,8,13,21 };
  68.  
  69.     BYTE    Value = (BYTE)Src[1];
  70.     UBYTE    Code;
  71.  
  72.         /* Skip the header information. */
  73.  
  74.     Src        += 2;
  75.     Size    -= 2;
  76.  
  77.         /* Run down the chunk... */
  78.  
  79.     while(Size--)
  80.     {
  81.         Code = *Src++;
  82.  
  83.             /* Add the top nibble delta. */
  84.  
  85.         Value += CodeToDelta[Code >> 4];
  86.  
  87.         *Dst++ = Value;
  88.  
  89.             /* Add the bottom nibble delta. */
  90.  
  91.         Value += CodeToDelta[Code & 0xF];
  92.  
  93.         *Dst++ = Value;
  94.     }
  95. }
  96.  
  97.     /* FreeSound(struct SoundInfo *SoundInfo):
  98.      *
  99.      *    Free sound handle and associated data.
  100.      */
  101.  
  102. VOID
  103. FreeSound(struct SoundInfo *SoundInfo)
  104. {
  105.     if(SoundInfo->SoundObject)
  106.         DisposeDTObject(SoundInfo->SoundObject);
  107.     else
  108.         FreeVecPooled(SoundInfo->SoundData);
  109.  
  110.     FreeVecPooled(SoundInfo);
  111. }
  112.  
  113.     /* LoadSound(STRPTR Name):
  114.      *
  115.      *    Load a sound file from disk.
  116.      */
  117.  
  118. struct SoundInfo *
  119. LoadSound(STRPTR Name,BOOL Warn)
  120. {
  121.     struct SoundInfo    *SoundInfo = NULL;
  122.     struct IFFHandle    *Handle;
  123.  
  124.         /* Allocate IFF handle for reading. */
  125.  
  126.     if(Handle = OpenIFFStream(Name,MODE_OLDFILE))
  127.     {
  128.         LONG SoundStops[3 * 2] =
  129.         {
  130.             ID_8SVX,ID_VHDR,
  131.             ID_8SVX,ID_CHAN,
  132.             ID_8SVX,ID_BODY
  133.         };
  134.  
  135.             /* Mark the chunks to stop at. */
  136.  
  137.         if(!StopChunks(Handle,SoundStops,3))
  138.         {
  139.             struct ContextNode *Chunk;
  140.             struct VoiceHeader Header;
  141.             SampleType Channel;
  142.             BOOL SingleChannel;
  143.             UBYTE Compression;
  144.  
  145.             Channel            = SAMPLE_STEREO;
  146.             SingleChannel    = TRUE;
  147.  
  148.                 /* Clear the voice header. */
  149.  
  150.             memset(&Header,0,sizeof(Header));
  151.  
  152.                 /* Scan for data... */
  153.  
  154.             while(!ParseIFF(Handle,IFFPARSE_SCAN))
  155.             {
  156.                 Chunk = CurrentChunk(Handle);
  157.  
  158.                     /* What did we find? */
  159.  
  160.                 switch(Chunk->cn_ID)
  161.                 {
  162.                         /* Looks like the basic voice header. */
  163.  
  164.                     case ID_VHDR:
  165.  
  166.                             /* Read the header. */
  167.  
  168.                         if(ReadIFFBytes(Handle,&Header,MIN(Chunk->cn_Size,sizeof(Header))))
  169.                         {
  170.                                 /* Compression type supported? */
  171.  
  172.                             if(Header.vh_Compression == CMP_NONE || Header.vh_Compression == CMP_FIBDELTA)
  173.                             {
  174.                                     /* Allocate the sound handle. */
  175.  
  176.                                 if(SoundInfo = (struct SoundInfo *)AllocVecPooled(sizeof(struct SoundInfo),MEMF_ANY | MEMF_CLEAR))
  177.                                 {
  178.                                         /* Install the rate, volume and length. */
  179.  
  180.                                     SoundInfo->Rate        = SysBase->ex_EClockFrequency * 5 / Header.vh_SamplesPerSec;
  181.                                     SoundInfo->Length    = Header.vh_OneShotHiSamples ? Header.vh_OneShotHiSamples : (Header.vh_RepeatHiSamples ? Header.vh_RepeatHiSamples : Header.vh_SamplesPerHiCycle);
  182.                                     SoundInfo->Volume    = (SoundConfig.Volume * ((Header.vh_Volume * MAX_VOLUME) / Unity)) / 100;
  183.  
  184.                                         /* Remember compression mode. */
  185.  
  186.                                     Compression        = Header.vh_Compression;
  187.                                 }
  188.                             }
  189.                         }
  190.  
  191.                         break;
  192.  
  193.                         /* Looks like sound channel information. */
  194.  
  195.                     case ID_CHAN:
  196.  
  197.                             /* Do we have a handle to manage it? */
  198.  
  199.                         if(SoundInfo)
  200.                         {
  201.                                 /* Read the channel information. */
  202.  
  203.                             if(ReadIFFBytes(Handle,&Channel,MIN(Chunk->cn_Size,sizeof(SampleType))))
  204.                             {
  205.                                     /* Stereo sound file? */
  206.  
  207.                                 if(Channel == SAMPLE_STEREO)
  208.                                     SingleChannel = FALSE;
  209.                             }
  210.                             else
  211.                             {
  212.                                 FreeVecPooled(SoundInfo);
  213.  
  214.                                 SoundInfo = NULL;
  215.                             }
  216.                         }
  217.  
  218.                         break;
  219.  
  220.                         /* Looks like the sound body data. */
  221.  
  222.                     case ID_BODY:
  223.  
  224.                             /* Do we have sound handle to manage it? */
  225.  
  226.                         if(SoundInfo)
  227.                         {
  228.                             BOOL Success = FALSE;
  229.  
  230.                             if(!SoundInfo->Length)
  231.                                 SoundInfo->Length = Chunk->cn_Size;
  232.  
  233.                                 /* Uncompressed raw data? */
  234.  
  235.                             if(Compression == CMP_NONE)
  236.                             {
  237.                                 ULONG Wanted;
  238.  
  239.                                 if(Channel == SAMPLE_STEREO && !SingleChannel)
  240.                                 {
  241.                                     Wanted = SoundInfo->Length * 2;
  242.  
  243.                                     if(Wanted > Chunk->cn_Size)
  244.                                     {
  245.                                         SoundInfo->Length /= 2;
  246.  
  247.                                         Wanted = SoundInfo->Length * 2;
  248.                                     }
  249.                                 }
  250.                                 else
  251.                                     Wanted = SoundInfo->Length;
  252.  
  253.                                 if(Chunk->cn_Size >= Wanted)
  254.                                 {
  255.                                         /* Allocate a buffer. */
  256.  
  257.                                     if(SoundInfo->SoundData = AllocVecPooled(Wanted,MEMF_ANY))
  258.                                     {
  259.                                             /* Read the data. */
  260.  
  261.                                         if(ReadIFFBytes(Handle,SoundInfo->SoundData,Wanted))
  262.                                             Success = TRUE;
  263.                                         else
  264.                                             FreeVecPooled(SoundInfo->SoundData);
  265.                                     }
  266.                                 }
  267.                             }
  268.                             else
  269.                             {
  270.                                 ULONG Wanted;
  271.  
  272.                                 if(Channel == SAMPLE_STEREO && !SingleChannel)
  273.                                 {
  274.                                     Wanted = SoundInfo->Length + 4;
  275.  
  276.                                     if(Wanted > Chunk->cn_Size)
  277.                                     {
  278.                                         SoundInfo->Length /= 2;
  279.  
  280.                                         Wanted = SoundInfo->Length * 2 + 4;
  281.  
  282.                                         SingleChannel = TRUE;
  283.                                     }
  284.                                 }
  285.                                 else
  286.                                     Wanted = SoundInfo->Length / 2 + 2;
  287.  
  288.                                 if(Chunk->cn_Size >= Wanted)
  289.                                 {
  290.                                     UBYTE *TempBuffer;
  291.  
  292.                                         /* Allocate a temporary decompression buffer. */
  293.  
  294.                                     if(TempBuffer = (UBYTE *)AllocVecPooled(Chunk->cn_Size,MEMF_ANY))
  295.                                     {
  296.                                             /* Read the compressed data. */
  297.  
  298.                                         if(ReadIFFBytes(Handle,TempBuffer,Chunk->cn_Size))
  299.                                         {
  300.                                             ULONG Length = SoundInfo->Length;
  301.  
  302.                                                 /* Allocate space for the uncompressed data. */
  303.  
  304.                                             if(SoundInfo->SoundData = AllocVecPooled(Length * 2,MEMF_ANY))
  305.                                             {
  306.                                                     /* Stereo sound file? */
  307.  
  308.                                                 if(!SingleChannel && Channel == SAMPLE_STEREO)
  309.                                                 {
  310.                                                     UBYTE *Data = SoundInfo->SoundData;
  311.  
  312.                                                         /* Unpack the stereo sound. */
  313.  
  314.                                                     DeltaUnpack(TempBuffer,                 Length / 2 + 2,Data);
  315.                                                     DeltaUnpack(TempBuffer + Length / 2 + 2,Length / 2 + 2,Data + Length);
  316.                                                 }
  317.                                                 else
  318.                                                 {
  319.                                                         /* Unpack the mono sound. */
  320.  
  321.                                                     DeltaUnpack(TempBuffer,Length / 2 + 2,SoundInfo->SoundData);
  322.                                                 }
  323.  
  324.                                                 Success = TRUE;
  325.                                             }
  326.                                         }
  327.  
  328.                                         FreeVecPooled(TempBuffer);
  329.                                     }
  330.                                 }
  331.                             }
  332.  
  333.                             if(!Success)
  334.                             {
  335.                                 FreeVecPooled(SoundInfo);
  336.  
  337.                                 SoundInfo = NULL;
  338.                             }
  339.                         }
  340.  
  341.                         break;
  342.                 }
  343.             }
  344.  
  345.                 /* Did we get what we wanted? */
  346.  
  347.             if(SoundInfo)
  348.             {
  349.                     /* Any sound data allocated? */
  350.  
  351.                 if(SoundInfo->SoundData)
  352.                 {
  353.                     UBYTE *Data = SoundInfo->SoundData;
  354.  
  355.                         /* Which kind of sound file did
  356.                          * we read?
  357.                          */
  358.  
  359.                     switch(Channel)
  360.                     {
  361.                             /* Left channel only. */
  362.  
  363.                         case SAMPLE_LEFT:
  364.  
  365.                             SoundInfo->LeftData = Data;
  366.                             break;
  367.  
  368.                             /* Right channel only. */
  369.  
  370.                         case SAMPLE_RIGHT:
  371.  
  372.                             SoundInfo->RightData = Data;
  373.                             break;
  374.  
  375.                             /* Two stereo channels. */
  376.  
  377.                         case SAMPLE_STEREO:
  378.  
  379.                                 /* One sound mapped to two voices. */
  380.  
  381.                             if(SingleChannel)
  382.                                 SoundInfo->LeftData = SoundInfo->RightData = Data;
  383.                             else
  384.                             {
  385.                                     /* Split the voice data. */
  386.  
  387.                                 SoundInfo->LeftData        = Data;
  388.                                 SoundInfo->RightData    = Data + SoundInfo->Length;
  389.                             }
  390.  
  391.                             break;
  392.                     }
  393.                 }
  394.                 else
  395.                 {
  396.                     FreeVecPooled(SoundInfo);
  397.  
  398.                     SoundInfo = NULL;
  399.                 }
  400.             }
  401.         }
  402.  
  403.         CloseIFFStream(Handle);
  404.     }
  405.  
  406.         /* Successful? */
  407.  
  408.     if(SoundInfo)
  409.         strcpy(SoundInfo->Name,Name);
  410.     else
  411.     {
  412.         if(DataTypesBase)
  413.         {
  414.             Object *Sound;
  415.  
  416.             if(Sound = NewDTObject(Name,
  417.                 DTA_SourceType,    DTST_FILE,
  418.                 DTA_GroupID,    GID_SOUND,
  419.                 SDTA_Volume,    (SoundConfig.Volume * MAX_VOLUME) / 100,
  420.                 SDTA_Cycles,    1,
  421.             TAG_DONE))
  422.             {
  423.                 struct VoiceHeader *Header;
  424.                 ULONG SampleLength;
  425.  
  426.                 SampleLength    = 0;
  427.                 Header            = NULL;
  428.  
  429.                 if(GetDTAttrs(Sound,
  430.                     SDTA_SampleLength,    &SampleLength,
  431.                     SDTA_VoiceHeader,    &Header,
  432.                 TAG_DONE) == 2)
  433.                 {
  434.                     if(SampleLength && Header)
  435.                     {
  436.                         ULONG Secs,Micro,Period;
  437.  
  438.                         Period    = Header->vh_SamplesPerSec;
  439.  
  440.                         Secs    = SampleLength / Period;
  441.                         Micro    = (1000000 / Period) * (SampleLength % Period);
  442.  
  443.                         if(SoundInfo = (struct SoundInfo *)AllocVecPooled(sizeof(struct SoundInfo),MEMF_ANY | MEMF_CLEAR))
  444.                         {
  445.                             strcpy(SoundInfo->Name,Name);
  446.  
  447.                             SoundInfo->SoundObject            = Sound;
  448.                             SoundInfo->SoundTime.tv_secs    = Secs;
  449.                             SoundInfo->SoundTime.tv_micro    = Micro;
  450.  
  451.                             return(SoundInfo);
  452.                         }
  453.                     }
  454.                 }
  455.  
  456.                 DisposeDTObject(Sound);
  457.             }
  458.         }
  459.  
  460.         if(Warn)
  461.             ShowRequest(Window,LocaleString(MSG_TERMSOUND_COULD_NOT_LOAD_SOUND_FILE_TXT),LocaleString(MSG_GLOBAL_CONTINUE_TXT),Name);
  462.     }
  463.  
  464.     return(SoundInfo);
  465. }
  466.  
  467.     /* ReplaySound():
  468.      *
  469.      *    Replay sound with given information (doubly-buffered).
  470.      */
  471.  
  472. STATIC VOID
  473. ReplaySound(struct SoundInfo *SoundInfo,struct IOAudio *SoundControlRequest,struct IOAudio *SoundRequestLeft,struct IOAudio *SoundRequestRight,struct BufferInfo *BufferInfo)
  474. {
  475.     UBYTE    *Left    = SoundInfo->LeftData,
  476.             *Right    = SoundInfo->RightData;
  477.     ULONG     Size    = SoundInfo->Length,Length;
  478.     LONG     Base    = 0;
  479.  
  480.     Length = MIN(BUFFER_SIZE,Size);
  481.  
  482.     Size -= Length;
  483.  
  484.         /* Left channel available? */
  485.  
  486.     if(!(((ULONG)SoundRequestLeft->ioa_Request.io_Unit) & (LEFT0F | LEFT1F)))
  487.         Left = NULL;
  488.  
  489.         /* Right channel available? */
  490.  
  491.     if(!(((ULONG)SoundRequestRight->ioa_Request.io_Unit) & (RIGHT0F | RIGHT1F)))
  492.         Right = NULL;
  493.  
  494.         /* Fill up left buffer. */
  495.  
  496.     if(Left)
  497.     {
  498.         CopyMem(Left,BufferInfo[Base].Buffer,Length);
  499.  
  500.         BufferInfo[Base].Size = Length;
  501.  
  502.         Left += Length;
  503.     }
  504.  
  505.         /* Fill up right buffer. */
  506.  
  507.     if(Right)
  508.     {
  509.         CopyMem(Right,BufferInfo[Base + 2].Buffer,Length);
  510.  
  511.         BufferInfo[Base + 2].Size = Length;
  512.  
  513.         Right += Length;
  514.     }
  515.  
  516.         /* Process sound data. */
  517.  
  518.     do
  519.     {
  520.             /* Block both channels. */
  521.  
  522.         SoundControlRequest->ioa_Request.io_Command = CMD_STOP;
  523.  
  524.         SendIO((struct IORequest *)SoundControlRequest);
  525.         WaitIO((struct IORequest *)SoundControlRequest);
  526.  
  527.             /* Any data for the left channel? */
  528.  
  529.         if(Left)
  530.         {
  531.             SoundRequestLeft->ioa_Request.io_Command    = CMD_WRITE;
  532.             SoundRequestLeft->ioa_Request.io_Flags        = ADIOF_PERVOL;
  533.             SoundRequestLeft->ioa_Period                = SoundInfo->Rate;
  534.             SoundRequestLeft->ioa_Volume                = SoundInfo->Volume;
  535.             SoundRequestLeft->ioa_Cycles                = 1;
  536.             SoundRequestLeft->ioa_Data                    = BufferInfo[Base].Buffer;
  537.             SoundRequestLeft->ioa_Length                = BufferInfo[Base].Size;
  538.  
  539.                 /* Get the left channel going. */
  540.  
  541.             BeginIO((struct IORequest *)SoundRequestLeft);
  542.         }
  543.  
  544.             /* Any data for the right channel? */
  545.  
  546.         if(Right)
  547.         {
  548.             SoundRequestRight->ioa_Request.io_Command    = CMD_WRITE;
  549.             SoundRequestRight->ioa_Request.io_Flags        = ADIOF_PERVOL;
  550.             SoundRequestRight->ioa_Period                = SoundInfo->Rate;
  551.             SoundRequestRight->ioa_Volume                = SoundInfo->Volume;
  552.             SoundRequestRight->ioa_Cycles                = 1;
  553.             SoundRequestRight->ioa_Data                    = BufferInfo[Base + 2].Buffer;
  554.             SoundRequestRight->ioa_Length                = BufferInfo[Base + 2].Size;
  555.  
  556.                 /* Get the right channel going. */
  557.  
  558.             BeginIO((struct IORequest *)SoundRequestRight);
  559.         }
  560.  
  561.             /* Start up both channels synchronously... */
  562.  
  563.         SoundControlRequest->ioa_Request.io_Command = CMD_START;
  564.  
  565.         SendIO((struct IORequest *)SoundControlRequest);
  566.         WaitIO((struct IORequest *)SoundControlRequest);
  567.  
  568.             /* Grab the other buffers. */
  569.  
  570.         Base ^= 1;
  571.  
  572.             /* Still any data left? */
  573.  
  574.         if(Size)
  575.         {
  576.                 /* Cut off the next slice. */
  577.  
  578.             Length = MIN(BUFFER_SIZE,Size);
  579.  
  580.             Size -= Length;
  581.  
  582.                 /* Left channel available? */
  583.  
  584.             if(Left)
  585.             {
  586.                 CopyMem(Left,BufferInfo[Base].Buffer,Length);
  587.  
  588.                 BufferInfo[Base].Size = Length;
  589.  
  590.                 Left += Length;
  591.             }
  592.  
  593.                 /* Right channel available? */
  594.  
  595.             if(Right)
  596.             {
  597.                 CopyMem(Right,BufferInfo[Base + 2].Buffer,Length);
  598.  
  599.                 BufferInfo[Base + 2].Size = Length;
  600.  
  601.                 Right += Length;
  602.             }
  603.  
  604.                 /* Last slice eaten? */
  605.  
  606.             if(!Size)
  607.             {
  608.                     /* Wait for sounds to terminate. */
  609.  
  610.                 if(Left)
  611.                     WaitIO((struct IORequest *)SoundRequestLeft);
  612.  
  613.                 if(Right)
  614.                     WaitIO((struct IORequest *)SoundRequestRight);
  615.  
  616.                     /* Block both channels. */
  617.  
  618.                 SoundControlRequest->ioa_Request.io_Command = CMD_STOP;
  619.  
  620.                 SendIO((struct IORequest *)SoundControlRequest);
  621.                 WaitIO((struct IORequest *)SoundControlRequest);
  622.  
  623.                     /* Any data for the left channel? */
  624.  
  625.                 if(Left)
  626.                 {
  627.                     SoundRequestLeft->ioa_Request.io_Command    = CMD_WRITE;
  628.                     SoundRequestLeft->ioa_Request.io_Flags        = ADIOF_PERVOL;
  629.                     SoundRequestLeft->ioa_Period                = SoundInfo->Rate;
  630.                     SoundRequestLeft->ioa_Volume                = SoundInfo->Volume;
  631.                     SoundRequestLeft->ioa_Cycles                = 1;
  632.                     SoundRequestLeft->ioa_Data                    = BufferInfo[Base].Buffer;
  633.                     SoundRequestLeft->ioa_Length                = BufferInfo[Base].Size;
  634.  
  635.                         /* Get the left channel going. */
  636.  
  637.                     BeginIO((struct IORequest *)SoundRequestLeft);
  638.                 }
  639.  
  640.                     /* Any data for the right channel? */
  641.  
  642.                 if(Right)
  643.                 {
  644.                     SoundRequestRight->ioa_Request.io_Command    = CMD_WRITE;
  645.                     SoundRequestRight->ioa_Request.io_Flags        = ADIOF_PERVOL;
  646.                     SoundRequestRight->ioa_Period                = SoundInfo->Rate;
  647.                     SoundRequestRight->ioa_Volume                = SoundInfo->Volume;
  648.                     SoundRequestRight->ioa_Cycles                = 1;
  649.                     SoundRequestRight->ioa_Data                    = BufferInfo[Base + 2].Buffer;
  650.                     SoundRequestRight->ioa_Length                = BufferInfo[Base + 2].Size;
  651.  
  652.                         /* Get the right channel going. */
  653.  
  654.                     BeginIO((struct IORequest *)SoundRequestRight);
  655.                 }
  656.  
  657.                     /* Start up both channels synchronously... */
  658.  
  659.                 SoundControlRequest->ioa_Request.io_Command = CMD_START;
  660.  
  661.                 SendIO((struct IORequest *)SoundControlRequest);
  662.                 WaitIO((struct IORequest *)SoundControlRequest);
  663.             }
  664.         }
  665.  
  666.             /* Wait for sounds to terminate. */
  667.  
  668.         if(Left)
  669.             WaitIO((struct IORequest *)SoundRequestLeft);
  670.  
  671.         if(Right)
  672.             WaitIO((struct IORequest *)SoundRequestRight);
  673.     }
  674.     while(Size);
  675. }
  676.  
  677.     /* PlaySound(struct SoundInfo *SoundInfo):
  678.      *
  679.      *    Replay a sound.
  680.      */
  681.  
  682. VOID
  683. PlaySound(struct SoundInfo *SoundInfo)
  684. {
  685.     if(SoundInfo->SoundObject)
  686.     {
  687.         struct timerequest *SoundTimeRequest;
  688.         struct MsgPort *SoundTimePort;
  689.  
  690.         SoundTimeRequest    = NULL;
  691.         SoundTimePort        = NULL;
  692.  
  693.         if(CreateTimeRequest(UNIT_VBLANK,&SoundTimeRequest,&SoundTimePort))
  694.         {
  695.             SoundTimeRequest->tr_node.io_Command    = TR_ADDREQUEST;
  696.             SoundTimeRequest->tr_time                = SoundInfo->SoundTime;
  697.  
  698.             SetSignal(0,PORTMASK(SoundTimePort));
  699.  
  700.             SendIO((struct IORequest *)SoundTimeRequest);
  701.  
  702.             DoMethod(SoundInfo->SoundObject,DTM_TRIGGER,NULL,STM_PLAY,NULL);
  703.  
  704.             WaitIO((struct IORequest *)SoundTimeRequest);
  705.  
  706.             DeleteTimeRequest(SoundTimeRequest,SoundTimePort);
  707.         }
  708.     }
  709.     else
  710.     {
  711.         struct BufferInfo *BufferInfo;
  712.  
  713.             /* Allocate sound buffers. */
  714.  
  715.         if(BufferInfo = (struct BufferInfo *)AllocVec(4 * sizeof(struct BufferInfo),MEMF_CHIP))
  716.         {
  717.             struct MsgPort *SoundPort;
  718.  
  719.                 /* Allocate an io replyport. */
  720.  
  721.             if(SoundPort = CreateMsgPort())
  722.             {
  723.                 struct IOAudio *SoundControlRequest;
  724.  
  725.                     /* Allocate the big sound control request. */
  726.  
  727.                 if(SoundControlRequest = (struct IOAudio *)CreateIORequest(SoundPort,sizeof(struct IOAudio)))
  728.                 {
  729.                     struct IOAudio *SoundRequestLeft;
  730.  
  731.                         /* Allocate the left channel sound request. */
  732.  
  733.                     if(SoundRequestLeft = (struct IOAudio *)CreateIORequest(SoundPort,sizeof(struct IOAudio)))
  734.                     {
  735.                         struct IOAudio *SoundRequestRight;
  736.  
  737.                             /* Allocate the right channel sound request. */
  738.  
  739.                         if(SoundRequestRight = (struct IOAudio *)CreateIORequest(SoundPort,sizeof(struct IOAudio)))
  740.                         {
  741.                             STATIC UBYTE TwoChannels[] =
  742.                             {
  743.                                 LEFT0F | RIGHT0F,
  744.                                 LEFT0F | RIGHT1F,
  745.                                 LEFT1F | RIGHT0F,
  746.                                 LEFT1F | RIGHT1F
  747.                             };
  748.  
  749.                             STATIC UBYTE LeftChannel[] =
  750.                             {
  751.                                 LEFT0F,
  752.                                 LEFT1F
  753.                             };
  754.  
  755.                             STATIC UBYTE RightChannel[] =
  756.                             {
  757.                                 RIGHT0F,
  758.                                 RIGHT1F
  759.                             };
  760.  
  761.                             UBYTE *AllocationMap;
  762.                             LONG AllocationSize;
  763.  
  764.                                 /* Determine the correct channel
  765.                                  * allocation map.
  766.                                  */
  767.  
  768.                             if(SoundInfo->LeftData)
  769.                             {
  770.                                 if(SoundInfo->RightData)
  771.                                 {
  772.                                     AllocationMap    = TwoChannels;
  773.                                     AllocationSize    = sizeof(TwoChannels);
  774.                                 }
  775.                                 else
  776.                                 {
  777.                                     AllocationMap    = LeftChannel;
  778.                                     AllocationSize    = sizeof(LeftChannel);
  779.                                 }
  780.                             }
  781.                             else
  782.                             {
  783.                                 AllocationMap    = RightChannel;
  784.                                 AllocationSize    = sizeof(RightChannel);
  785.                             }
  786.  
  787.                                 /* Set up for sound channel allocation. */
  788.  
  789.                             SoundControlRequest->ioa_Request.io_Message.mn_Node.ln_Pri    = 127;
  790.                             SoundControlRequest->ioa_Request.io_Command                    = ADCMD_ALLOCATE;
  791.                             SoundControlRequest->ioa_Request.io_Flags                    = ADIOF_NOWAIT | ADIOF_PERVOL;
  792.                             SoundControlRequest->ioa_Data                                = AllocationMap;
  793.                             SoundControlRequest->ioa_Length                                = AllocationSize;
  794.  
  795.                                 /* Open audio.device, allocating the sound
  796.                                  * channels on the fly.
  797.                                  */
  798.  
  799.                             if(!OpenDevice(AUDIONAME,NULL,(struct IORequest *)SoundControlRequest,NULL))
  800.                             {
  801.                                     /* Clone the sound control request. */
  802.  
  803.                                 CopyMem(SoundControlRequest,SoundRequestLeft,    sizeof(struct IOAudio));
  804.                                 CopyMem(SoundControlRequest,SoundRequestRight,    sizeof(struct IOAudio));
  805.  
  806.                                     /* Separate the channels. */
  807.  
  808.                                 SoundRequestLeft ->ioa_Request.io_Unit = (struct Unit *)((ULONG)SoundRequestLeft ->ioa_Request.io_Unit & (LEFT0F  | LEFT1F));
  809.                                 SoundRequestRight->ioa_Request.io_Unit = (struct Unit *)((ULONG)SoundRequestRight->ioa_Request.io_Unit & (RIGHT0F | RIGHT1F));
  810.  
  811.                                     /* Replay the sound... */
  812.  
  813.                                 ReplaySound(SoundInfo,SoundControlRequest,SoundRequestLeft,SoundRequestRight,BufferInfo);
  814.  
  815.                                     /* Do the big cleanup. */
  816.  
  817.                                 CloseDevice((struct IORequest *)SoundControlRequest);
  818.                             }
  819.  
  820.                             DeleteIORequest(SoundRequestRight);
  821.                         }
  822.  
  823.                         DeleteIORequest(SoundRequestLeft);
  824.                     }
  825.  
  826.                     DeleteIORequest(SoundControlRequest);
  827.                 }
  828.  
  829.                 DeleteMsgPort(SoundPort);
  830.             }
  831.  
  832.             FreeVec(BufferInfo);
  833.         }
  834.     }
  835. }
  836.  
  837.     /* SoundLoad(LONG Sound,BOOL Warn):
  838.      *
  839.      *    Loads or frees a sound slot.
  840.      */
  841.  
  842. STATIC BOOL
  843. SoundLoad(LONG Sound,BOOL Warn)
  844. {
  845.     struct SoundInfo **Info;
  846.     BOOL Success;
  847.     STRPTR Name;
  848.  
  849.     Info    = &SoundSlot[Sound];
  850.     Success    = FALSE;
  851.  
  852.         /* Which sound file name are we to pick? */
  853.  
  854.     switch(Sound)
  855.     {
  856.         case SOUND_BELL:
  857.  
  858.             Name = SoundConfig.BellFile;
  859.             break;
  860.  
  861.         case SOUND_CONNECT:
  862.  
  863.             Name = SoundConfig.ConnectFile;
  864.             break;
  865.  
  866.         case SOUND_DISCONNECT:
  867.  
  868.             Name = SoundConfig.DisconnectFile;
  869.             break;
  870.  
  871.         case SOUND_GOODTRANSFER:
  872.  
  873.             Name = SoundConfig.GoodTransferFile;
  874.             break;
  875.  
  876.         case SOUND_BADTRANSFER:
  877.  
  878.             Name = SoundConfig.BadTransferFile;
  879.             break;
  880.  
  881.         case SOUND_RING:
  882.  
  883.             Name = SoundConfig.RingFile;
  884.             break;
  885.  
  886.         case SOUND_VOICE:
  887.  
  888.             Name = SoundConfig.VoiceFile;
  889.             break;
  890.  
  891.         case SOUND_ERROR:
  892.  
  893.             Name = SoundConfig.ErrorNotifyFile;
  894.             break;
  895.     }
  896.  
  897.         /* Is a file name available? */
  898.  
  899.     if(Name[0])
  900.     {
  901.             /* Sound slot already initialized? */
  902.  
  903.         if(*Info)
  904.         {
  905.                 /* Did the file name change? */
  906.  
  907.             if(Stricmp((*Info)->Name,Name))
  908.             {
  909.                     /* Free the sound slot. */
  910.  
  911.                 FreeSound(*Info);
  912.  
  913.                     /* Try to load the sound slot. */
  914.  
  915.                 if(*Info = LoadSound(Name,Warn))
  916.                 {
  917.                         /* Remember the file name. */
  918.  
  919.                     strcpy((*Info)->Name,Name);
  920.  
  921.                     Success = TRUE;
  922.                 }
  923.             }
  924.             else
  925.                 Success = TRUE;
  926.         }
  927.         else
  928.         {
  929.                 /* Try to load the sound slot. */
  930.  
  931.             if(*Info = LoadSound(Name,Warn))
  932.             {
  933.                     /* Remember the file name. */
  934.  
  935.                 strcpy((*Info)->Name,Name);
  936.  
  937.                 Success = TRUE;
  938.             }
  939.         }
  940.     }
  941.     else
  942.     {
  943.             /* Does the slot still contain any sound? */
  944.  
  945.         if(*Info)
  946.         {
  947.                 /* Free the slot. */
  948.  
  949.             FreeSound(*Info);
  950.  
  951.             *Info = NULL;
  952.         }
  953.  
  954.         Success = TRUE;
  955.     }
  956.  
  957.     return(Success);
  958. }
  959.  
  960.     /* SoundServer(VOID):
  961.      *
  962.      *    Replay a sound.
  963.      */
  964.  
  965. STATIC VOID SAVE_DS STACKARGS
  966. SoundServer(LONG Index)
  967. {
  968.         /* Get access to the sound slots. */
  969.  
  970.     SafeObtainSemaphoreShared(&SoundSemaphore);
  971.  
  972.         /* Replay the sound. */
  973.  
  974.     PlaySound(SoundSlot[Index]);
  975.  
  976.     Forbid();
  977.  
  978.         /* Release access to the sound slots. */
  979.  
  980.     ReleaseSemaphore(&SoundSemaphore);
  981. }
  982.  
  983.     /* SoundExit():
  984.      *
  985.      *    Free allocated sound resources.
  986.      */
  987.  
  988. VOID
  989. SoundExit()
  990. {
  991.     LONG i;
  992.  
  993.     if(SoundInitialized)
  994.         ObtainSemaphore(&SoundSemaphore);
  995.  
  996.         /* Free the slots. */
  997.  
  998.     for(i = 0 ; i < SOUND_COUNT ; i++)
  999.     {
  1000.         if(SoundSlot[i])
  1001.         {
  1002.             FreeSound(SoundSlot[i]);
  1003.  
  1004.             SoundSlot[i] = NULL;
  1005.         }
  1006.     }
  1007.  
  1008.     if(SoundInitialized)
  1009.         ReleaseSemaphore(&SoundSemaphore);
  1010. }
  1011.  
  1012.     /* SoundInit():
  1013.      *
  1014.      *    Allocate resources required for sound replaying.
  1015.      */
  1016.  
  1017. VOID
  1018. SoundInit()
  1019. {
  1020.         /* Sound access semaphore available? */
  1021.  
  1022.     if(!SoundInitialized)
  1023.     {
  1024.         InitSemaphore(&SoundSemaphore);
  1025.         SoundInitialized = TRUE;
  1026.     }
  1027.  
  1028.         /* Preload sounds if necessary. */
  1029.  
  1030.     if(SoundConfig.Preload)
  1031.     {
  1032.         LONG i;
  1033.  
  1034.         for(i = 0 ; i < SOUND_COUNT ; i++)
  1035.             SoundLoad(i,TRUE);
  1036.     }
  1037. }
  1038.  
  1039.     /* SoundPlay(LONG Sound):
  1040.      *
  1041.      *    Play a certain sound slot.
  1042.      */
  1043.  
  1044. VOID
  1045. SoundPlay(LONG Sound)
  1046. {
  1047.     if(SoundConfig.Volume > 0)
  1048.     {
  1049.         BOOL DoBeep = FALSE;
  1050.  
  1051.             /* Sound access semaphore available? */
  1052.  
  1053.         if(SoundInitialized)
  1054.         {
  1055.                 /* Check to see if we are currently playing a
  1056.                  * sound.
  1057.                  */
  1058.  
  1059.             if(AttemptSemaphore(&SoundSemaphore))
  1060.             {
  1061.                 ReleaseSemaphore(&SoundSemaphore);
  1062.  
  1063.                     /* Release any other sound if necessary. */
  1064.  
  1065.                 if(!SoundConfig.Preload)
  1066.                 {
  1067.                     LONG i;
  1068.  
  1069.                     for(i = 0 ; i < SOUND_COUNT ; i++)
  1070.                     {
  1071.                         if(i != Sound && SoundSlot[i])
  1072.                         {
  1073.                             FreeSound(SoundSlot[i]);
  1074.  
  1075.                             SoundSlot[i] = NULL;
  1076.                         }
  1077.                     }
  1078.                 }
  1079.  
  1080.                     /* Load the sound slot. */
  1081.  
  1082.                 SoundLoad(Sound,FALSE);
  1083.  
  1084.                     /* Slot filled? */
  1085.  
  1086.                 if(!SoundSlot[Sound])
  1087.                     DoBeep = TRUE;
  1088.                 else
  1089.                 {
  1090.                         /* Fire off the sound server task. */
  1091.  
  1092.                     if(!LocalCreateTask("term Sound Task",ThisProcess->pr_Task.tc_Node.ln_Pri + 10,(TASKENTRY)SoundServer,4000,1,Sound))
  1093.                         DoBeep = TRUE;
  1094.                 }
  1095.             }
  1096.         }
  1097.  
  1098.             /* Check if the default sound should be played. */
  1099.  
  1100.         if(DoBeep)
  1101.             Beep();
  1102.     }
  1103. }
  1104.